<script setup lang="ts">
import { computed, ref, h } from 'vue'
import { NDropdown, NButton, NIcon } from 'naive-ui'
import { Copy, CheckmarkDoneCircleOutline } from '@vicons/ionicons5'
import { convertFileSrc } from '@tauri-apps/api/tauri'
import { documentDir, join } from '@tauri-apps/api/path'
import MarkerService from './services/marker.service'

const identifier = 'tech.jiyun.ascum'
const markerService = new MarkerService()
const mapUrl = ref('')
const scale = ref(1.0)
const offsetX = ref(0)
const offsetY = ref(0)
const style = computed(() => ({
  transform: `translate(${offsetX.value}px, ${offsetY.value}px) scale(${scale.value})`
}))
const options = [
  {
    label: '标记当前',
    key: 'player'
  },
  {
    label: '添加标记',
    key: 'marker',
    children: [
      {
        label: '新地堡',
        key: 'mi_bunker2'
      },
      {
        label: '旧地堡',
        key: 'mi_bunker'
      },
      {
        label: '加油站',
        key: 'mi_ressource_fuel'
      },
      {
        label: '刷车点',
        key: 'mi_vehicle'
      },
      {
        label: '工作台',
        key: 'mi_ressource_work'
      },
      {
        label: '交易区',
        key: 'mi_jy'
      },
      {
        label: '砖块',
        key: 'mi_zhuan'
      },
      {
        label: '水泥',
        key: 'mi_shuini'
      },
      {
        label: '沙石',
        key: 'mi_shashi'
      }
    ]
  }
]
const menuStyle = ref({
  x: -500,
  y: -500,
  show: false
})
const markerVisiable = ref([
  ...(options[1].children || []).map(v => ({ ...v, visiable: false }))
])
const markers = computed(() => [
  {
    x: -500,
    y: -500,
    opacity: '0',
    type: 'player'
  },
  ...markerService.markers.value.map(v => {
    if (markerVisiable.value.find(vv => vv.visiable && vv.key === v.type)) {
      return {
        ...v,
        opacity: '1'
      }
    }
    return {
      ...v,
      opacity: '0'
    }
  })
])
const regions = new Array(25).fill(0).map((_, i) => {
  return {
    left: (i % 5) * 20 + '%',
    top: Math.floor(i / 5) * 20 + '%',
    label: String.fromCharCode(68 - Math.floor(i / 5)).replace('@', 'Z') + (4 - i % 5)
  }
})

documentDir().then(async d => {
  mapUrl.value = convertFileSrc(await join(d, identifier, 'map.jpg'))
})

let isMoving = false
// eslint-disable-next-line @typescript-eslint/no-explicit-any
function onWheel (evt: any) {
  if (isMoving === true) {
    return
  }
  const x0 = scale.value * evt.offsetX
  const y0 = scale.value * evt.offsetY
  scale.value = Math.max(1, Math.min(4, scale.value + evt.wheelDelta / 1200))
  offsetX.value -= (scale.value * evt.offsetX - x0)
  offsetY.value -= (scale.value * evt.offsetY - y0)
  const offsetLimit = window.outerHeight - window.outerHeight * scale.value
  offsetX.value = Math.max(offsetLimit, Math.min(0, offsetX.value))
  offsetY.value = Math.max(offsetLimit, Math.min(0, offsetY.value))
}
function onMouseDown (evt: MouseEvent) {
  if (evt.button === 1) {
    isMoving = true
  }
}
function onMouseUp () {
  if (isMoving === true) {
    isMoving = false
  }
}
function onMouseMove (evt: MouseEvent) {
  if (!isMoving) {
    return
  }
  offsetX.value += evt.movementX
  offsetY.value += evt.movementY
  const offsetLimit = window.outerHeight - window.outerHeight * scale.value
  offsetX.value = Math.max(offsetLimit, Math.min(0, offsetX.value))
  offsetY.value = Math.max(offsetLimit, Math.min(0, offsetY.value))
}
function onContextMenu (evt: MouseEvent) {
  menuStyle.value.x = evt.pageX
  menuStyle.value.y = evt.pageY
  menuStyle.value.show = true
}

function onMenu (type: string) {
  if (type === 'player') {
    markers.value[0] = {
      x: (menuStyle.value.x - offsetX.value) / scale.value,
      y: (menuStyle.value.y - offsetY.value) / scale.value,
      opacity: '1',
      type: 'player'
    }
  } else {
    markerService.add((menuStyle.value.x - offsetX.value) / scale.value, (menuStyle.value.y - offsetY.value) / scale.value, type)
    markerVisiable.value.find(v => v.key === type)!.visiable = true
  }
  menuStyle.value.x = -500
  menuStyle.value.y = -500
  menuStyle.value.show = false
}

function onRemove (i: number) {
  markerService.remove(i - 1)
}

function renderDropdownLabel (opt: Any) {
  return h(
    'div',
    {
      className: 'marker-visiable-option',
      style: {
        color: opt.visiable ? '#63e2b7' : '#888'
      }
    },
    {
      default: () => [h('img', { src: 'markers/' + opt.key + '.png' }), opt.label, h(NIcon, { size: 18, color: opt.visiable ? '#63e2b7' : '#888' }, { default: () => h(CheckmarkDoneCircleOutline) })]
    }
  )
}

function onVisiableChange (key: string) {
  const item = markerVisiable.value.find(v => v.key === key)
  item!.visiable = !item?.visiable
}
</script>

<template>
  <div class="map" @mousedown="onMouseDown" @mouseup="onMouseUp" @mousemove="onMouseMove"
    @contextmenu.prevent="onContextMenu" @wheel="onWheel">
    <div class="map-img" :style="style">
      <img :src="mapUrl">
      <div class="grid-lins"></div>
      <span class="region-label" v-for="(region, i) of regions" :key="i" :style="{left: region.left, top: region.top }">{{ region.label }}</span>
      <div class="marker" v-for="(marker, i) of markers" :key="i" :class="marker.type"
        :style="{ '--left': marker.x, '--top': marker.y, opacity: marker.opacity ?? '1', '--scale': 1 / scale, 'background-image': `url(markers/${marker.type}.png)` }"
        @wheel.stop @dblclick="onRemove(i)"></div>
    </div>
    <n-dropdown placement="bottom-start" trigger="manual" :x="menuStyle.x" :y="menuStyle.y" :options="options"
      :show="menuStyle.show" :on-clickoutside="() => menuStyle.show = false" @select="onMenu" />

    <n-dropdown class="marker-visiable-menu" :options="markerVisiable" placement="bottom-end" :render-label="renderDropdownLabel" @select="onVisiableChange">
      <n-button ghost type="primary" class="marker-visiable-menu-btn">
        <n-icon><copy /></n-icon>
      </n-button>
    </n-dropdown>
  </div>
</template>

<style scoped lang="less">
.map {
  width: 100vw;
  height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  position: relative;
  pointer-events: all !important;
  transform-origin: 0 0;

  .map-img {
    height: 100%;
    position: absolute;
    top: 0;
    left: 0;
    transform-origin: 0 0;

    img {
      height: 100%;
      user-select: none;
      -webkit-user-drag: none;
    }
    .grid-lins {
      position: absolute;
      top: 0;
      left: 0;
      width: 100%;
      height: 100%;
      background-image: linear-gradient(transparent,transparent 99%,#0006 50%),
          linear-gradient(to right,transparent,transparent 99%,#0006 50%);
      background-size:20% 20%;
      pointer-events: none;
    }
    .region-label {
      position: absolute;
      font-size: 20px;
      font-weight: bold;
      margin: 5px 10px;
    }
    .marker {
      position: absolute;
      transform-origin: 50% 100%;
      top: 0;
      left: 0;
      transform: translate(calc(1px * var(--left) - 16px), calc(1px * var(--top) - 32px)) scale(var(--scale));
      width: 32px;
      height: 32px;
      content: " ";
      z-index: 10;
      background-size: contain;

      &.player {
        pointer-events: none;
        transform: translate(calc(1px * var(--left) - 8px), calc(1px * var(--top) - 8px)) scale(var(--scale));
        transform-origin: 50% 50%;
        width: 16px;
        height: 16px;
        background-color: #F00;
        border-radius: 50%;
      }
    }
  }

  .context-menu {
    position: absolute;
    left: calc(1px * var(--left));
    top: calc(1px * var(--top));
    width: 100px;
    z-index: 1;
    background: var(--modal-color);
    border-radius: 4px;
    box-sizing: 0 0 3px 0 #000;
    transition: opacity 0.175s;

    .item {
      padding: 5px;
      text-align: center;
      cursor: pointer;

      &:first-of-type {
        padding-top: 10px;
      }

      &:last-of-type {
        padding-bottom: 10px;
      }

      &:hover {
        background-color: var(--button-color-2-hover);
      }
    }
  }
  :deep(.marker-visiable-menu-btn) {
    position: absolute;
    right: 12px;
    top: 12px;
    width: 32px;
    height: 32px;
    padding: 0;
  }
}
</style>
<style lang="less">
body {
  background-color: transparent !important;
  background: transparent !important;
  pointer-events: none !important;
}

.n-dropdown-menu {
  margin-top: 0 !important;
}
.marker-visiable-menu {
  margin-top: -32px !important;
}
.marker-visiable-option {
  display: flex;
  align-items: center;
  justify-content: space-between;
  width: 100px;
  img {
    height: 22px;
    margin-right: auto;
  }
  i {
    margin-left: auto;
  }
}
</style>
